iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
Build on Google AI

單鐵的人生如履薄冰!AI 教練 APP 30天開發旅程,你說能走到最後嗎?系列 第 16

Day 16 | 介面實作 (1):打造跑者基本資料的專屬表單,為 AI 準備精準 Context

  • 分享至 

  • xImage
  •  

前言:AI 教練也需要認識你

在 Day 9 設計後端 Prompt 範本時,我們預留了 {{TARGET_RACE}}(目標賽事)與 {{CURRENT_LEVEL}}(體能現況)等動態參數。

要讓雲端的 AI 教練給出真正客製化的課表,App 必須先收集跑者的基本數據(身高、體重、每週可練跑天數與目標)。

https://ithelp.ithome.com.tw/upload/images/20260825/20165043Aui0LhLqCk.png

在 Web 中,表單是 <form> 包裹 <input>;但在 React Native 中沒有 form 概念,且存在手機端最常見的「虛擬鍵盤遮擋」問題。今天將以最佳實踐完成防雷表單。

觀念轉換:React Native 表單的三大物理法則

  1. 無 <form> 標籤,狀態全由 useState 控制:各欄位值由 React State 即時同步,點擊送出按鈕時直接讀取 State。
  2. 使用 onChangeText 取代 onChange:直接接收輸入的字串值,無需透過 e.target.value 提取。
  3. 處理虛擬鍵盤 (Virtual Keyboard):彈出的鍵盤若未經處理會遮擋下半部輸入框與按鈕,需透過 KeyboardAvoidingView 與 ScrollView 協同處理。

動手實作**:精準生成防雷表單**

Prompt:

「我正在開發 KAKERU 馬拉松 APP,請幫我以最佳實踐實作個人設定頁面。
資料欄位 (使用 useState 管理):
暱稱、目標賽事 (字串)
身高、體重、每週練跑天數 (數字)
UI 與架構要求:
使用 KeyboardAvoidingView 與 ScrollView,點擊空白處可收起鍵盤。
身高與體重欄位並排,並顯示單位 (cm/kg)。
底部需保留 safe inset 空間,確保送出按鈕不被底部懸浮導覽列遮擋。
品牌色為亮橘色 (#FF5722),卡片採圓角與淡灰邊框設計。」

產生的程式碼:

export default function ProfileScreen() {
  const insets = useSafeAreaInsets();

  // 1. 宣告 State 收集跑者參數
  const [nickname, setNickname] = useState('');
  const [height, setHeight] = useState('');
  const [weight, setWeight] = useState('');
  const [targetRace, setTargetRace] = useState('');
  const [weeklyDays, setWeeklyDays] = useState('');

  const handleSave = () => {
    const runnerData = { nickname, height: Number(height), weight: Number(weight), targetRace, weeklyDays: Number(weeklyDays) };
    console.log('準備傳送給 AI 教練的資料:', runnerData);
    Alert.alert('儲存成功', '跑者資料已就緒,準備於明日串接 AI 課表生成!');
  };

  return (
    <SafeAreaView style={styles.safeArea} edges={['top', 'left', 'right']}>
      {/* 2. 關鍵防雷:鍵盤推升與點擊空白處收合 */}
      <KeyboardAvoidingView 
        style={{ flex: 1 }} 
        behavior={Platform.OS === 'ios' ? 'padding' : undefined}
      >
        <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
          <ScrollView
            contentContainerStyle={[
              styles.scrollContent,
              { paddingBottom: insets.bottom + 100 } // 避開底部懸浮導覽列
            ]}
            keyboardShouldPersistTaps="handled"
          >
            {/* 3. 表單卡片輸入區 */}
            <View style={styles.card}>
              <Text style={styles.label}>跑者暱稱</Text>
              <TextInput style={styles.input} placeholder="例如:Kakeru" value={nickname} onChangeText={setNickname} />

              {/* 身高與體重並排 */}
              <View style={styles.row}>
                <View style={styles.halfField}>
                  <Text style={styles.label}>身高 (cm)</Text>
                  <TextInput style={styles.input} keyboardType="numeric" placeholder="175" value={height} onChangeText={setHeight} />
                </View>
                <View style={styles.halfField}>
                  <Text style={styles.label}>體重 (kg)</Text>
                  <TextInput style={styles.input} keyboardType="numeric" placeholder="68" value={weight} onChangeText={setWeight} />
                </View>
              </View>

              {/* ... 目標賽事與每週天數輸入框 (結構同上,略) ... */}
            </View>

            {/* 4. 送出按鈕 */}
            <TouchableOpacity style={styles.saveButton} onPress={handleSave}>
              <Text style={styles.saveButtonText}>儲存並準備生成課表</Text>
            </TouchableOpacity>
          </ScrollView>
        </TouchableWithoutFeedback>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

// ... 樣式表 StyleSheet (省略) ...

細節處理

  1. 鍵盤互動 (TouchableWithoutFeedback + Keyboard.dismiss):使用者點擊畫面任一空白處即可自然收起鍵盤。
  2. keyboardShouldPersistTaps="handled":避免使用者點擊按鈕時因鍵盤收起而被吞掉點擊事件。
  3. 動態 Safe Inset 預留:透過 useSafeAreaInsets 計算底部邊距,避免懸浮 Tab Bar 遮蓋「儲存按鈕」的風險。
  4. 防呆機制:要確保使用者有這卻輸入資訊,以此也需要有防呆機制。

避免使用者沒有輸入就儲存的防呆機制:
https://ithelp.ithome.com.tw/upload/images/20260825/20165043bGpXAOm3ZJ.png

使用者輸入完成後顯示儲存成功:
https://ithelp.ithome.com.tw/upload/images/20260825/201650433QG8XTjmBH.png

今日總結與明日預告

今天完成了跑者個人資料表單,並處理了鍵盤彈出與安全邊距問題,資料已就緒儲存於本地狀態。明天(Day 17) 前後端大串接!我們將 React Native 現有開發的內容,將跑者資料傳送至 GCP Cloud Run 上的 Spring Boot AI 教練 API,正式打通 AI 課表生成流程!我們明天見!!


上一篇
Day 15 | 導覽列與路由:實作首頁、課表頁、個人頁面的絲滑切換
下一篇
Day 17 | 前後端串接:透過 Axios 呼叫 Cloud Run,並用 AI 跨端排查 Guardrail 障礙
系列文
單鐵的人生如履薄冰!AI 教練 APP 30天開發旅程,你說能走到最後嗎?17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言